package cn.yuanqiao.es.service.impl;


import cn.yuanqiao.common.constant.Constants;
import cn.yuanqiao.common.core.context.ResponseUtils;
import cn.yuanqiao.common.core.domain.entity.SysRole;
import cn.yuanqiao.common.domain.DataScopeStaticValue;
import cn.yuanqiao.common.exception.ServiceException;
import cn.yuanqiao.common.utils.SecurityUtils;
import cn.yuanqiao.es.domain.QueryFile;
import cn.yuanqiao.es.mapper.ElasticsearchApiMapper;
import cn.yuanqiao.es.service.AppRetrievalService;
import cn.yuanqiao.es.service.ElasticsearchIndex;
import cn.yuanqiao.es.service.ElasticsearchTemplate;

import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.mozilla.universalchardet.UniversalDetector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 小程序
 *
 * @ProjectName: JZSDAS
 * @Package: cn.yuanqiao.es.service.impl
 * @ClassName: AppRetrievalServiceImpl
 * @Author: lenovo
 * @Description: hbWang
 * @Date: 2023/11/8 11:25
 * @Version: 1.0
 */
@Service
public class AppRetrievalServiceImpl implements AppRetrievalService {

    @Autowired
    ElasticsearchApiMapper elasticsearchApiMapper;

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    ElasticsearchIndex elasticsearchIndex;

    /**
     * 门类信息
     *
     * @param menuId
     * @return
     */
    @Override
    public List<Map<String, Object>> categoryList(String menuId) {
        String tenantCode = SecurityUtils.getTenantCode();
        StringBuilder sql = new StringBuilder("");
        sql.append(" select c.GROUP_ID,c.ID,c.NAME,c.TYPE,c.FONDS_CODE from " + tenantCode + Constants.BIG_TABLE_NAME);
        sql.append(" c where c.IS_DEL = 0 ");
        //查询门类信息
        List<Map<String, Object>> categoryList = elasticsearchApiMapper.selectLeftJoinTableData(" GROUP_ID, ID,NAME,TYPE,FONDS_CODE ", "", sql.toString());
        return categoryList;
    }

    /**
     * 查询展示字段信息
     *
     * @param json
     * @return
     */
    @Override
    public List<Map<String, String>> queryFields(JSONObject json) {
        //获取当前登录用户信息SecurityUtils.getTenantCode()
        String categoryId = json.getString("categoryId"); //门类id
        String menuId = json.getString("menuId"); //菜单id
        String groupId = json.getString("groupId"); //菜单id
        String tenantCode = SecurityUtils.getTenantCode();
        StringBuilder sql = new StringBuilder("");
        if (StringUtils.isNotBlank(categoryId)) {
            List<Map<String, Object>> dataList = elasticsearchApiMapper.selectTableData(tenantCode +
                    Constants.TABLE_YQ_APP, " ID,JIANQUERY,JIANORDER ", " MENU_ID = '" + menuId + "' "
                    + " and CATEGORY_ID = '" + categoryId + "' ");
            if (dataList != null && dataList.size() > 0) {
                String appData = dataList.get(0).get("JIANQUERY") == null ? "" : dataList.get(0).get("JIANQUERY").toString();
                if (StringUtils.isNotBlank(appData)) {
                    sql.append(" and tn.FIELD_NAME in  ('" + appData.replace(",", "','") + "') ");
                }
            }

        }
        sql.append(" and tn.TYPE = 0 AND tn.IS_HIDDEN = 0  AND tn.IS_SYSTEM = 1 ");
        sql.append(" and tn.GROUP_ID =  '" + groupId + "' ");
        //查询元数据方案信息
        List<Map<String, Object>> dataList = elasticsearchApiMapper.selectTableData
                (tenantCode + Constants.BIG_TABLE_M_DATA_LIST, " tn.FIELD_CAPTION,tn.FIELD_NAME,tn.IS_QUERY,tn.SHOWTYPE,tn.TYPE ",
                        sql.toString());
        List<Map<String, String>> tabulationData = dataList.stream().collect(Collectors.groupingBy(c -> c.get("FIELD_NAME"))).values().stream().map(a ->
        {
            Map<String, String> mm = new HashMap<>();
            mm.put("FIELD_NAME", String.valueOf(a.get(0).get("FIELD_NAME")));
            mm.put("FIELD_CAPTION", a.stream().map(dd -> String.valueOf(dd.get("FIELD_CAPTION"))).distinct().collect(Collectors.joining("/")));
            mm.put("SHOWTYPE", String.valueOf(a.get(0).get("SHOWTYPE")));
            return mm;
        }).collect(Collectors.toList());
        return tabulationData;
    }

    /**
     * 查询数据信息
     *
     * @param queryFile
     * @return
     */
    @Override
    public Map<String, Object> searchApp(QueryFile queryFile) {
        //获取当前租户信息SecurityUtils.getTenantCode()
        String tenantCode = SecurityUtils.getTenantCode();
        //判断索引是否存在
        boolean exists = elasticsearchIndex.existsIndex(tenantCode.toLowerCase());
        if (!exists) {
            throw new ServiceException("请先创建索引!");
        }

        Map<String, Object> map11 = new HashMap<>();
        SearchResponse<Object> searchResponse = elasticsearchTemplate.searchApp(queryFile, tenantCode);
        if (ObjectUtils.isEmpty(searchResponse)) return map11;
        List<Object> hitList = searchResponse.hits().hits().stream().map(m -> m.source()).collect(Collectors.toList());
        List<Map<String, Object>> result = new ArrayList<>();
        for (Object a : hitList) {
            Map<String, Object> map = com.alibaba.fastjson2.JSONObject.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(a), new TypeReference<Map<String, Object>>() {
            });
            result.add(map);
        }
        long value = searchResponse.hits().total().value();
        List<Map<String, Object>> aa = authority(result, queryFile.getMenuId());
        Map<String, Object> aaa = new HashMap<>();
        aaa.put("00000", "111111111");
        aa.add(0, aaa);
        aa.add(1, aaa);
        map11.put("data", authority(result, queryFile.getMenuId()));
        map11.put("recordsFiltered:", Integer.parseInt(String.valueOf(value)));
        map11.put("recordsTotal:", Integer.parseInt(String.valueOf(value)));
        return map11;
    }

    /**
     * 查询文件列表
     *
     * @param json
     * @return
     */
    @Override
    public List<Map<String, Object>> queryEfile(JSONObject json) {
        String categoryId = json.getString("categoryId"); //门类id
        String daId = json.getString("daId"); //档案id
        String tenantCode = SecurityUtils.getTenantCode();
        //查询门类信息
        String efiletable = elasticsearchApiMapper.selectAppData(tenantCode + Constants.BIG_TABLE_NAME, " EFILE_TABLE_NAME ", " ID='" + categoryId + "' ");
        List<Map<String, Object>> efileList = elasticsearchApiMapper.selectEFileTableDataApp(efiletable, " and CON_TABLE_ID = '" + daId + "' ");
        return efileList;
    }


    /**
     * 预览
     *
     * @param request
     * @param response docId   文件docid  *
     *                 daId       档案id     daId和categoryId二选一必填
     *                 categoryId  门类id
     * @throws Exception
     */
    @Override
    public void view(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Long doc_id = Long.parseLong(request.getParameter("docId"));
        String daId = String.valueOf(request.getParameter("daId"));
        String categoryId = String.valueOf(request.getParameter("categoryId"));
        String tenantCode = SecurityUtils.getTenantCode();
        String categoryTableName = tenantCode + Constants.BIG_TABLE_NAME;
        String efiletable = "";
        if (null == daId || "null".equals(daId)) {
            efiletable = elasticsearchApiMapper.selectAppData(categoryTableName, " EFILE_TABLE_NAME ", " ID='" + categoryId + "' ");
        }
        Map<String, Object> document = elasticsearchApiMapper.viewByDocid(doc_id, efiletable, tenantCode + "_YQDATRANSDOC");
        String url = document.get("DOC_MNT") + File.separator + document.get("PATH");
        if (url.equals("null")) {
            response.sendError(404, "File not found!");
            return;
        }
        response.reset(); // 非常重要
        ResponseUtils.defaultResponse(response);
        if ("TXT".equals(document.get("DOC_FILE_TYPE"))) {
            readTxtFile(url, document.get("DOC_NAME").toString(), response);
        } else {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "inline; filename=\"" + document.get("DOC_NAME").toString() + "\"");
            BufferedInputStream br = new BufferedInputStream(new FileInputStream(new File(url)));
            byte[] buf = new byte[1024];
            int len = 0;
            OutputStream out = response.getOutputStream();
            while ((len = br.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            System.gc();
            br.close();
            out.close();
        }
    }

    private void readTxtFile(String filePath, String fileName, HttpServletResponse response) {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath))) {
            UniversalDetector detector = new UniversalDetector(null);
            byte[] buf = new byte[4096];
            int nread;

            while ((nread = bis.read(buf)) > 0 && !detector.isDone()) {
                detector.handleData(buf, 0, nread);
            }

            detector.dataEnd();
            //读取txt文件的编码格式
            String encoding = detector.getDetectedCharset();
            detector.reset();
            //以确定的编码格式读取文件
            OutputStream out = response.getOutputStream();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), encoding))) {
                StringBuilder sb = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                    sb.append(System.lineSeparator());
                }
                String fileContent = sb.toString();
                // 之后你可以将fileContent作为你的响应内容
                response.setContentType("text/plain; charset=" + encoding); // 设置正确的编码格式
                response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\"");
                out.write(fileContent.getBytes(encoding));
            }
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 借阅权限
     *
     * @param dataList
     * @param menuId
     * @return
     */
    public List<Map<String, Object>> authority(List<Map<String, Object>> dataList, String menuId) {
        if (ObjectUtils.isEmpty(dataList)) {
            return null;
        }
        //is_borrowing_car   0 不需要借阅 1 需要借阅

        List<SysRole> roles = SecurityUtils.getLoginUser().getSysUser().getRoles();
        boolean allMatch = false;
        if (roles != null && roles.size() > 0) {
            allMatch = roles.stream().anyMatch(a -> a.getRoleName().trim().equals("档案管理员"));
        }
        for (Map<String, Object> data : dataList) {
            int isBorrowingCar = 1;
            if (allMatch) {
                data.put("is_borrowing_car", "0");
                continue;
            }
            if (data.containsKey("IS_OPENS")) {
                //IS_OPENS  0 不开放  1 开放
                String isOpens = data.get("IS_OPENS").toString();
                if ("1".equals(isOpens)) {
                    data.put("is_borrowing_car", "0");
                    continue;
                }
            }
            if (!data.containsKey("CREATE_ID")) {
                data.put("is_borrowing_car", "1");
                continue;
            }
            String id = data.get("CREATE_ID").toString();
            if (StringUtils.isBlank(id)) {
                data.put("is_borrowing_car", "1");
                continue;
            }
            String tableName = data.get("sub_table_name").toString();
            String tablenametype = tableName.substring(tableName.length() - 3, tableName.length() - 2);
            String field = " ta.CREATE_ID ";
            if ("X".equalsIgnoreCase(tablenametype)) {
                field = field + " , ta.IS_OPENS ";
            }
            Map<String, Object> mapUser = elasticsearchApiMapper.selectUserData(field, tableName, id);
            if (mapUser != null) {
                if (isBorrowingCar == 1){
                    if (mapUser.containsKey("CREATE_ID")) {
                        StringBuilder sql = new StringBuilder();
                        if ("F".equalsIgnoreCase(tablenametype)) {//档案层
                            sql.append(" FILE_TABLE_NAME = '");
                        } else if ("V".equalsIgnoreCase(tablenametype)) {//案卷层
                            sql.append(" FOLDER_TABLE_NAME = '");
                        } else if ("X".equalsIgnoreCase(tablenametype)) {//项目层
                            sql.append(" ITEM_TABLE_NAME = '");
                        }
                        sql.append(tableName).append("' ");
                        String tenantCode = SecurityUtils.getTenantCode().toUpperCase();
                        //创建人id
                        String createId = mapUser.get("CREATE_ID").toString();
                        String categoryId = elasticsearchApiMapper.selectAppData(tenantCode + Constants.BIG_TABLE_NAME, " ID ", sql.toString());
                        if (roleTree(menuId, createId, categoryId)) {
                            isBorrowingCar = 0;
                        }
                    }
                }
            }
            data.put("is_borrowing_car", isBorrowingCar);
        }
        return dataList;
    }

    /**
     * 角色判断
     *
     * @param menuId
     * @param createId
     * @param categoryId
     * @return
     */
    public boolean roleTree(String menuId, String createId, String categoryId) {
        String tenantCode = SecurityUtils.getTenantCode().toUpperCase();
        boolean b = false;
        StringBuilder sqlString = new StringBuilder();
        List<SysRole> roles = SecurityUtils.getLoginUser().getSysUser().getRoles();
        Long dept = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        if (roles != null && roles.size() > 0) {
            for (SysRole role : roles) {
                //查询角色关联档案门类
                sqlString.append(" id in ( select tree_id from ").append(tenantCode + Constants.ABLE_TREES)
                        .append(" where  ROLE_ID = '").append(role.getRoleId()).append("' AND MENU_ID = '").append(menuId).append("' ) and category_id = '")
                        .append(categoryId).append("' ");
                String countCgId = elasticsearchApiMapper.selectAppData(tenantCode + Constants.ABLE_TREES, " COUNT(*) ", sqlString.toString());
                if (!"0".equals(countCgId)) {
                    String dataScope = role.getDataScope();
                    String userIdNum = "0";
                    if (DataScopeStaticValue.DATA_SCOPE_ALL.equals(dataScope)) {
                        b = true;
                        return b;
                    } else if (DataScopeStaticValue.DATA_SCOPE_CUSTOM.equals(dataScope)) {
                        sqlString.append(" su.dept_id in ( select dept_id from sys_role_dept where ROLE_ID = '")
                                .append(role.getRoleId()).append("' ) and su.user_id= '").append(createId).append("' ");
                        userIdNum = elasticsearchApiMapper.selectAppData(" sys_user su ", " COUNT(*) ", sqlString.toString());
                    } else if (DataScopeStaticValue.DATA_SCOPE_DEPT.equals(dataScope)) {
                        sqlString.append(" su.dept_id in ( select dept_id from sys_dept where dept_id = '")
                                .append(dept).append("' ) and su.user_id=  '").append(createId).append("' ");
                        userIdNum = elasticsearchApiMapper.selectAppData(" sys_user su ", " COUNT(*) ", sqlString.toString());
                    } else if (DataScopeStaticValue.DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
                        sqlString.append(" su.dept_id in ( select dept_id from sys_dept where dept_id = '")
                                .append(dept).append("' or find_in_set( '").append(dept).append("' , ancestors )) and su.user_id=  '")
                                .append(createId).append("' ");
                        userIdNum = elasticsearchApiMapper.selectAppData(" sys_user su ", " COUNT(*) ", sqlString.toString());
                    } else if (DataScopeStaticValue.DATA_SCOPE_SELF.equals(dataScope)) {
                        if (String.valueOf(SecurityUtils.getUserId()).equals(createId)) {
                            b = true;
                            return b;
                        }
                    }
                    if (!"0".equals(userIdNum)) {
                        b = true;
                        return b;
                    }
                }
            }
        }
        return b;
    }

}
